package us.versus.them.isod;

/* based on http://jice.nospam.googlepages.com/basicdungeongeneration */
class SplitDigger {

	var min:Int;
	var max:Int;

	public function new( ?min:Int, ?max:Int ) {
		if ( null == min  ) {
			min = 3;
		}
		if ( null == max ) {
			max = 9;
		}
		this.min = min;
		this.max = max;
	}

	public function dig( map:Array< Array< String > > ) {
		split( true, map, 0, 0, map[ 0 ].length, map.length, min, max );
	}

	////

	public function isWall( map, x:Int, y:Int ) {
		return '#' == getAt( map, x, y );
	}

	public function getAt( map, x:Int, y:Int ) {
		return map[ y ][ x ];
	}


	public function setAt( map, v, x:Int, y:Int ) {
		map[ y ][ x ] = v;
	}

	////

	public function split( fu:Bool, map:Array< Array< String > >, x:Int, y:Int, w:Int, h:Int, min:Int, max:Int ) : Bool {
/*
		trace( 
			x + ',' + y + '+' + 
			w + 'x' + h + 
			'=' + (w*h) + ' v/s ' + min + ' & ' + max 
		);
*/
		var roomed = false;
		if ( w < max && h < max ) {
			roomed = dig_room( ' ', map, x, y, w, h );
		} else {
			//fu = Math.random() < 0.5;
			if ( fu ) {
				var nuW = Math.floor( w / 4 + Math.random() * w / 2 );
				//nuW = Math.floor( w / 2 );
				nuW = Math.floor( w / 2 + 4 * Math.random() - 4 * Math.random() );
				//trace( "nuW = " + nuW );
				if ( nuW > 3 ) {
					split( !fu, map , x       , y , nuW, h, min, max );
					split( !fu, map , x + nuW , y , w - nuW, h, min, max );
					horizontal_tunnel( map, x, y, w, h, nuW );
				} else { 
					roomed = dig_room( '.', map, x, y, w, h );
				}
			} else {
				var nuH = Math.floor(  h / 4 + Math.random() * h / 2 );
				//nuH = Math.floor( h / 2 );
				nuH - Math.floor( h /2 + 4 * Math.random() - 4 * Math.random() );
				//trace( 'nuH = ' + nuH );
				if ( nuH > 3 ) {
					split( !fu, map , x, y      , w, nuH    , min, max );
					split( !fu, map , x, y + nuH, w, h- nuH , min, max );
					vertical_tunnel( map, x, y, w, h, nuH );
				} else {
					roomed = dig_room( '_', map, x, y, w, h );
				}
			}
		}
		return roomed;
	}

	public function bigR( w, h ) {
		return if ( w < h ) { 
			w / h;
		} else {
			h / w;
		}
	}

	public function dig_room( c:String, map:Array< Array< String > >, x:Int, y:Int, w:Int, h:Int ) {
		var dug = false;
		//trace( 'bigR ' + w + 'x' + h + '=' + bigR( w, h ) );
		if ( 2 < w && 2 < h ) {//&& bigR( w, h ) > 0.5 ) {
			digOut( c, map, x, y, w, h );
			dug = true;
		}
		return dug;
	}

	public function digOut( c:String, map:Array< Array< String > >, x:Int, y:Int, w:Int, h:Int ) {
		for ( fy in y + 1  ... y + h - 1 ) {
			for ( fx in x + 1  ... x + w - 1 ) {
				setAt( map, c, fx, fy );
			}
		}
	}

	public function dig_horizontal_to_freedom( map, x0:Int, x1:Int, y:Int ) {
		for ( x in x0 + 1 ... x1 ) {
			//trace( 'hall dig ' + x + ',' + y );
			if ( isWall( map, x, y ) ) {
				setAt( map, '/', x, y );
			} else {
				break;
			}
		}
	}

	public function horizontal_tunnel( map, x:Int, y:Int, w:Int, h:Int, nuW:Int ) {
		var found = false;
		var search_y = 0;
		var search_x = x + nuW - 1;
		while ( !found && search_x > x ) {

			// search from middle down
			search_y = Math.floor( y + h / 2 );
			while ( search_y < y + h ) {
				found = !isWall( map, search_x, search_y );
				if ( found ) break;
				search_y++;
			}

			if ( !found ) {
				// search down to middle
				search_y = y;
				while ( search_y < y + h / 2 ) {
					found = !isWall( map, search_x, search_y );
					if ( found ) break;
					search_y++;
				}
			}

			if ( found ) break;
			search_x--;
		}
		if ( found ) {
			// TODO: make sure this tunnel can actually reach the other room!
			//trace( 'found is ' + found + ' at ' + search_x + ',' + search_y );
			dig_horizontal_to_freedom( map, search_x, x + w - 1, search_y );
		}
	}

	public function dig_vertical_to_freedom( map, x:Int, y0:Int, y1:Int ) {
		for ( y in y0 + 1 ... y1 ) {
			//trace( 'hall vdig ' + x + ',' + y );
			if ( isWall( map, x, y ) ) {
				setAt( map, '!', x, y );
			} else {
				break;
			}
		}
	}

	public function vertical_tunnel( map, x:Int, y:Int, w:Int, h:Int, nuH:Int ) {
		var found = false;
		var search_x = 0;
		var search_y = y + nuH - 1;
		while ( !found && search_y > y ) {

			// search from middle down
			search_x = Math.floor( x + w / 2 );
			while ( search_x < x + w ) {
				found = !isWall( map, search_x, search_y );
				if ( found ) break;
				search_x++;
			}

			if ( !found ) {
				// search down to middle
				search_x = x;
				while ( search_x < x + w / 2 ) {
					found = !isWall( map, search_x, search_y );
					if ( found ) break;
					search_x++;
				}
			}

			if ( found ) break;
			search_y--;
		}
		if ( found ) {
			// TODO: make sure this tunnel can actually reach the other room!
			//trace( 'found is ' + found + ' at ' + search_x + ',' + search_y );
			dig_vertical_to_freedom( map, search_x, search_y, y + h - 1 );
		}
	}
}
